package com.mika.music.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mika.music.constants.Constant;
import com.mika.music.model.User;
import com.mika.music.service.UserService;
import com.mika.music.utils.BCryptUtil;
import com.mika.music.utils.ResponseBodyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @RequestMapping("/login")
    public ResponseBodyMessage<Boolean> login(String userName, String password, HttpServletRequest request) {
        // 1. 进行参数校验
        // 2. 查询数据库, 对密码进行校验
        // 3. 密码校验成功，设置 session, 返回结果
        log.info("login，接收参数 userName: " + userName + ", password: " + password);
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
            return new ResponseBodyMessage<>(-2, "用户或密码不能为空", false);
        }

        // 先根据 userName，去 redis 中找到对应的 userId
        // 规定 key: userName:用户名   value: userId
        String username = "userName:" + userName;
        String id = stringRedisTemplate.opsForValue().get(username);
        log.info("从 redis 找到 id: " + id);

        if (StringUtils.hasLength(id)) {
            // 查询 redis，构造 key:  user:info:id    value: {id:"1", userName:"zhangsan", password: "123"}
            String key = "user:info:" + id;
            String value = stringRedisTemplate.opsForValue().get(key);
            // 能查找到用户
            if (StringUtils.hasLength(value)) {
                try {
                    User userRedis = objectMapper.readValue(value, User.class);
                    // 说明已经在 redis 中查找到了对应数据，则进行校验
                    log.info("从 redis 查找到 user: " + userRedis);
                    if (BCryptUtil.verify(password, userRedis.getPassword())) {
                        // 校验成功，存入 session
                        userRedis.setPassword("");
                        request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY, userRedis);
                        return new ResponseBodyMessage<>(200, null, true);
                    } else {
                        return new ResponseBodyMessage<>(-1, "用户名或者密码错误", false);
                    }
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
        }


        // 到了这里，说明 redis 中一定没有存储对应用户的数据
        User user = userService.getUserByName(userName);
        log.info("login，user: " + user);
        if (user == null || !BCryptUtil.verify(password, user.getPassword())) {
            return new ResponseBodyMessage<>(-1, "用户名或者密码错误", false);
        }

        String key = "user:info:" + user.getId();
        // 说明此时 redis 还没有对应的数据，那就存入 redis 中。(设置 30 天的过期时间)
        String valueSave = null;
        try {
            valueSave = objectMapper.writeValueAsString(user);
            stringRedisTemplate.opsForValue().set(username, String.valueOf(user.getId()), Duration.ofDays(30));
            stringRedisTemplate.opsForValue().set(key, valueSave, Duration.ofDays(30));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }


        user.setPassword("");
        request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY, user);
        return new ResponseBodyMessage<>(200, null, true);
    }

    @RequestMapping("/register")
    public ResponseBodyMessage<Boolean> register(String userName, String password) throws JsonProcessingException {
        // 1. 进行参数校验
        // 2. 查询数据库，看看用户名是否被注册
        // 3. 如果用户名没被注册，则根据用户输入的密码来生成密文
        // 4. 调用新增用户方法。
        log.info("register，接收参数 userName: " + userName + ", password: " + password);
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
            return new ResponseBodyMessage<>(-2, "用户或密码不能为空", false);
        }

        // 去 redis 中查找 userName 是否存在
        // 查询 redis，构造 key:  user:info:userName    value: {id:"1", userName:"zhangsan", password: "123"}
        String username = "userName:" + userName;
        String id = stringRedisTemplate.opsForValue().get(username);
        String key = "user:info:" + id;
        String value = stringRedisTemplate.opsForValue().get(key);
        // 判断结果是否合法
        if (StringUtils.hasLength(value)) {
            User userRedis = objectMapper.readValue(value, User.class);
            // 说明已经在 redis 中查找到了对应数据
            log.info("从 redis 查找到 user: " + userRedis);
            // 说明用户已经存在，不能注册
            return new ResponseBodyMessage<>(-1, "用户名已经被注册", false);
        }


        // 到了这里说明 redis 中没有该用户，则还需要去 mysql 中查找
        User user = userService.getUserByName(userName);
        log.info("register，user: " + user);
        if (user == null) {
            // 如果用户名没被注册，则需要新增用户
            User registerUser = new User(userName, BCryptUtil.encrypt(password));
            Integer result = userService.addUser(registerUser);
            if (result <= 0) {
                return new ResponseBodyMessage<>(-1, "注册失败，请联系管理员", false);
            }
        } else {
            // 说明用户名已经被注册，应该提醒用户换一个用户名注册。
            return new ResponseBodyMessage<>(-1, "用户名已经被注册", false);
        }
        return new ResponseBodyMessage<>(200, null, true);
    }
}
